Skip to content

feat(loyalty): add loyalty to purchase requests and a loyalty read API - #34

Merged
dinosoeren merged 1 commit into
mainfrom
feat/loyalty-purchase-field-and-read-api
Jul 28, 2026
Merged

feat(loyalty): add loyalty to purchase requests and a loyalty read API#34
dinosoeren merged 1 commit into
mainfrom
feat/loyalty-purchase-field-and-read-api

Conversation

@dinosoeren

@dinosoeren dinosoeren commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Two additive, backward-compatible changes to the public API.

Loyalty on purchase requests (egress). Adds an optional loyalty sub-payload to the RegisterPayment and ConfirmPayment requests. It describes the player's standing in a shop's active loyalty program at purchase time — points balance, current and previous tier, distance to the next tier and milestone, the next milestone's reward, and an effective points multiplier (the current tier's points-per-dollar rate relative to the tier below it, 1.0 at the lowest tier). The field is present only for shops with an active loyalty campaign, so requests for all other shops are byte-identical to before.

Loyalty read API (ingress). Adds a new read-only Loyalty service, authenticated with HMAC over the /sdk/studio/{shop_id} surface, with two endpoints:

  • GET /sdk/studio/{shop_id}/loyalty — the shop's active campaign configuration: tiers (ordered by starting points) and milestones (ordered by points needed).
  • GET /sdk/studio/{shop_id}/loyalty/players/{player_id} — a single player's loyalty standing.

Both the purchase field and the player endpoint reuse one shared Loyalty message. The loyalty read API is included in the primary hosted Web Shop API spec.

Notes

  • Additive only: new optional fields and a new service. buf breaking passes against main.
  • Regenerated docs/gen/swagger.v1.json via make check.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Note

Medium Risk
Additive proto and OpenAPI only, but it extends purchase callback contracts and documents new partner-facing loyalty endpoints that implementations must honor consistently.

Overview
Adds loyalty to the public API in two additive ways: partner backends can receive loyalty context on purchase webhooks, and can query loyalty configuration and player standing over the existing HMAC /sdk/studio ingress surface.

Purchase egress (Register/Confirm Payment) gains an optional loyalty field (PlayerLoyaltyState) with campaign id, points balance and delta, tier ids, progress to next tier/milestone, next milestone rewards, and pointsMultiplierPermille. It is omitted when the shop has no active campaign so non-loyalty payloads stay unchanged.

New ingress LoyaltyService exposes GET /sdk/studio/{shopId}/loyalty (active campaign tiers and nested milestones/rewards) and GET /sdk/studio/{shopId}/loyalty/players/{playerId} (player standing). OpenAPI is merged into the ingress spec (renamed Stash Studio Read API to cover catalog + loyalty) with regenerated docs/gen swagger.

Reviewed by Cursor Bugbot for commit 9b78509. Bugbot is set up for automated code reviews on this repo. Configure here.

@dinosoeren
dinosoeren force-pushed the feat/loyalty-purchase-field-and-read-api branch from e848b16 to 9289a98 Compare July 27, 2026 19:28
Comment thread docs/config/swagger-merger-config.json Outdated
@dinosoeren
dinosoeren force-pushed the feat/loyalty-purchase-field-and-read-api branch 5 times, most recently from a0f0454 to f3bf598 Compare July 28, 2026 04:55
Comment thread server/egress/shop/v1/loyalty.proto Outdated
@dinosoeren
dinosoeren force-pushed the feat/loyalty-purchase-field-and-read-api branch 6 times, most recently from 4549cef to 35efe77 Compare July 28, 2026 07:44

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 35efe77. Configure here.

Comment thread server/egress/shop/v1/loyalty.proto
@dinosoeren
dinosoeren force-pushed the feat/loyalty-purchase-field-and-read-api branch 2 times, most recently from cf0c56d to a6277ef Compare July 28, 2026 08:10
Loyalty standing snapshot (PlayerLoyaltyState) on egress purchase
requests and the loyalty read API. The egress and ingress loyalty
messages are fully self-contained per API: each PlayerLoyaltyState nests
its own Milestone and MilestoneRewardItem, and the ingress config
LoyaltyMilestone nests its own MilestoneRewardItem, so ingress and egress
share no loyalty types. Milestone rewards are lists; the snapshot's
next_milestone carries the milestone id plus all rewards. Numeric fields
use uint32 (xp_delta int32); tier ids and xp_to_next fields carry optional
presence. The points multiplier is a fixed-point permille integer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dinosoeren
dinosoeren force-pushed the feat/loyalty-purchase-field-and-read-api branch from a6277ef to 9b78509 Compare July 28, 2026 08:36
@dinosoeren
dinosoeren merged commit 3637c58 into main Jul 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant